package controllers

import (
	"fmt"
	"io/ioutil"
	"net/http"
	"os"
	"path/filepath"
	"regexp"
	"time"

	"github.com/golang/glog"

	authapi "eccgateway/pkg/api/auth"
	"eccgateway/pkg/config"
	authsvc "eccgateway/pkg/services/auth"
	imagesvc "eccgateway/pkg/services/image"
	"eccgateway/pkg/util"
)

type ImageController struct{}

var (
	username         string
	password         string
	registryEndpoint string
)

const (
	regular    = "^[a-z0-9]+(?:[._-][a-z0-9]+)*/[a-zA-Z0-9-]+:[a-zA-Z0-9-._]+$"
	defaultDir = "/tmp/eccgateway/"
)

func (c ImageController) UploadImage(w http.ResponseWriter, r *http.Request) {
	defer r.Body.Close()
	info, err := util.GetUserInfo(r.Header.Get(authapi.ParseInfo))
	if err != nil {
		glog.Errorf("get user info from header failed, err: %v", err)
		util.ReturnErrorResponseInResponseWriter(w, http.StatusBadRequest, err.Error())
		return
	}

	file, _, err := r.FormFile("image")
	if err != nil {
		util.ReturnErrorResponseInResponseWriter(w, http.StatusBadRequest, fmt.Sprintf("request file read failed, %v", err))
		return
	}
	tag := r.Form["tag"]
	if len(tag) == 0 {
		util.ReturnErrorResponseInResponseWriter(w, http.StatusBadRequest, fmt.Sprintf("tag is null"))
		return
	}
	newTag := tag[0]
	re, err := regexp.MatchString(regular, newTag)
	if re == false {
		util.ReturnErrorResponseInResponseWriter(w, http.StatusBadRequest, fmt.Sprintf("tag format is wrong, %v", err))
		return
	}

	requestBody, err := ioutil.ReadAll(file)
	if err != nil {
		util.ReturnErrorResponseInResponseWriter(w, http.StatusBadRequest, fmt.Sprintf("request body read failed, %v", err))
		return
	}

	nowTime := fmt.Sprintf("%d", time.Now().UnixNano())
	tarPath := filepath.Join(defaultDir, nowTime+".tar")
	err = prepareEnvironment(tarPath)
	if err != nil {
		util.ReturnErrorResponseInResponseWriter(w, http.StatusInternalServerError, fmt.Sprintf("%v", err))
		return
	}
	err = ioutil.WriteFile(tarPath, requestBody, 666)
	if err != nil {
		glog.Errorf("save body failed, err: %v", err)
		util.ReturnErrorResponseInResponseWriter(w, http.StatusInternalServerError, fmt.Sprintf("save body failed, %v", err))
		return
	}
	defer os.Remove(tarPath)

	userSecret, err := authsvc.GetUserSecret(info.Name)
	if err != nil {
		glog.Errorf("get user secret failed, err: %v", err)
		util.ReturnErrorResponseInResponseWriter(w, http.StatusInternalServerError, fmt.Sprintf("get user secret failed, %v", err))
		return
	}
	registryEndpoint = config.GetConfig().String("HarborAddress")
	imagePush := imagesvc.NewImagePush(tarPath, filepath.Join(defaultDir, nowTime), registryEndpoint, info.Name, userSecret.Password, false)
	errCode, err := imagePush.Push(newTag)
	if errCode != http.StatusOK || err != nil {
		glog.Errorf("push image failed, tag: %v, username: %v, errCode: %v, err: %v", tag, info.Name, errCode, err)
		util.ReturnErrorResponseInResponseWriter(w, errCode, fmt.Sprintf("%v", err))
		return
	}

}

func prepareEnvironment(tarPath string) error {
	var err error
	if !util.IsExist(defaultDir) {
		err = os.Mkdir(defaultDir, 666)
		if err != nil {
			glog.Errorf("create default dir failed, err: %v", err)
			return fmt.Errorf("create default dir failed, %v", err)
		}
	}
	if util.IsExist(tarPath) {
		err = os.Remove(tarPath)
		if err != nil {
			glog.Errorf("remove default tar failed, err: %v", err)
			return fmt.Errorf("remove default tar failed, %v", err)
		}
	}

	return nil
}
